package ms.jasim.framework;

import ms.jasim.model.Actor;
import ms.jasim.model.Capability;
import ms.jasim.model.CustomizableObject;
import ms.jasim.model.Evaluator;
import ms.jasim.model.Goal;
import ms.jasim.model.JasimModel;
import ms.jasim.model.items.PropertyDescriptor;
import ms.jasim.pddl.PddlPredicate;
import ms.jasim.pddl.PddlSolution.Functor;
import ms.jasim.pddl.PddlSolution.PddlAction;

@IEvaluator.Info(Name = "Cost/Benefit Quotient", Description = "", Components = { "Value", "Benefit", "Cost" })
public class CBQEvaluator implements IEvaluator {

	private final float DEFAULT_COST = 1.0f;
	
	float score = Float.NaN;
	float benefit = Float.NaN;
	float cost = Float.NaN;
	
	
	@Override
	public EvaluatorResult evaluate(IJasimAppContext context, JasimModel model, Evaluator item, Iterable<PddlAction> actions) {
		
		cost = benefit = 0;
		PropertyDescriptor workEffortDescriptor  = model.findPropertyDescriptor(Capability.class, PddlPredicate.WORK_EFFORT);
		PropertyDescriptor workSatDescriptor  = model.findPropertyDescriptor(Capability.class, PddlPredicate.WORK_SAT);
		PropertyDescriptor workTimeDescriptor  = model.findPropertyDescriptor(Capability.class, PddlPredicate.TIME_EFFORT);
		
		for (PddlAction a : actions) {
			if (a.getFunctor() == Functor.SATISFIES) {
				Actor act = model.getActors().get(a.getArgument(0));
				Goal goal = model.getGoals().get(a.getArgument(1));
				Capability cap = act.findCapability(goal);
				if (cap != null) {
					int time = getValue(cap, workTimeDescriptor, 1);
					cost += getValue(cap, workEffortDescriptor, 1) + time / 5;
					benefit += getValue(cap, workSatDescriptor, 1);
				}
			} else
				cost += DEFAULT_COST;
		}

		score = cost != 0 ? (benefit) / (cost)
				: Float.NaN;
		
		return new EvaluatorResult(CBQEvaluator.class, new float[] { score, benefit, cost });
	}

	private int getValue(CustomizableObject obj, PropertyDescriptor propDescriptor, int defaultValue) {
		if (propDescriptor == null)
			return defaultValue;
		return (Integer)obj.resolveProperty(propDescriptor).getValue(null);
	}

	@Override
	public EvaluatorResult combine(EvaluatorResult a, EvaluatorResult b) {
		EvaluatorResult result = a.clone();
		result.setValue(1, result.getValue(1) + b.getValue(1));
		result.setValue(2, result.getValue(2) + b.getValue(2));
		result.setValue(0, result.getValue(1) / result.getValue(2));
		return result;
	}

}
